Emberveil sourcegame/2006Scape Server/src/main/java/org/apollo/cache/archive/Archive.java
package org.apollo.cache.archive;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apollo.util.BufferUtil;
import org.apollo.util.CompressionUtil;
/**
* Represents an archive.
*
* @author Graham
*/
public final class Archive {
/**
* Decodes the archive in the specified buffer.
*
* @param buffer The buffer.
* @return The archive.
* @throws IOException If there is an error decompressing the archive.
*/
public static Archive decode(ByteBuffer buffer) throws IOException {
int extractedSize = BufferUtil.readUnsignedMedium(buffer);
int size = BufferUtil.readUnsignedMedium(buffer);
boolean extracted = false;
if (size != extractedSize) {
byte[] compressed = new byte[size];
byte[] decompressed = new byte[extractedSize];
buffer.get(compressed);
CompressionUtil.debzip2(compressed, decompressed);
buffer = ByteBuffer.wrap(decompressed);
extracted = true;
}
int entryCount = buffer.getShort() & 0xFFFF;
int[] identifiers = new int[entryCount];
int[] extractedSizes = new int[entryCount];
int[] sizes = new int[entryCount];
for (int i = 0; i < entryCount; i++) {
identifiers[i] = buffer.getInt();
extractedSizes[i] = BufferUtil.readUnsignedMedium(buffer);
sizes[i] = BufferUtil.readUnsignedMedium(buffer);
}
ArchiveEntry[] entries = new ArchiveEntry[entryCount];
for (int entry = 0; entry < entryCount; entry++) {
ByteBuffer entryBuffer;
if (!extracted) {
byte[] compressed = new byte[sizes[entry]];
byte[] decompressed = new byte[extractedSizes[entry]];
buffer.get(compressed);
CompressionUtil.debzip2(compressed, decompressed);
entryBuffer = ByteBuffer.wrap(decompressed);
} else {
byte[] buf = new byte[extractedSizes[entry]];
buffer.get(buf);
entryBuffer = ByteBuffer.wrap(buf);
}
entries[entry] = new ArchiveEntry(identifiers[entry], entryBuffer);
}
return new Archive(entries);
}
/**
* The entries in this archive.
*/
private final ArchiveEntry[] entries;
/**
* Creates a new archive.
*
* @param entries The entries in this archive.
*/
public Archive(ArchiveEntry[] entries) {
this.entries = entries;
}
/**
* Gets an {@link ArchiveEntry} by its name.
*
* @param name The name.
* @return The entry.
* @throws FileNotFoundException If the entry could not be found.
*/
public ArchiveEntry getEntry(String name) throws FileNotFoundException {
int hash = hash(name);
for (ArchiveEntry entry : entries) {
if (entry.getIdentifier() == hash) {
return entry;
}
}
throw new FileNotFoundException("Could not find entry: " + name + ".");
}
/**
* Hashes the specified string into an integer used to identify an {@link ArchiveEntry}.
*
* @param name The name of the entry.
* @return The hash.
*/
public static int hash(String name) {
return name.toUpperCase().chars().reduce(0, (hash, character) -> hash * 61 + character - 32);
}
}